#pragma once
#include <fstream>
#include "rectangle.h"
#include "drawable.h"
using namespace std;

#include <windows.h>
void gotoxy(int x, int y){
COORD point = {x, y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), point);
}


struct Map : public Drawable
{
	int width, height, x, y;
	char ** map;

	Map()
		:width(0),height(0),map(0),x(0),y(0)
	{}

	/**
	 * @param a_filename c-string filename of the file that is 
	 * formatted "width height\n[map data]"
	 * @return true, the map was loaded without issue
	 */
	bool load(char * a_filename)
	{
		ifstream infile(a_filename);
		if(!infile.good())
			return false;
		infile >> width >> height;
		if(width < 0 || height < 0)
			return false;
		infile.get();	// feed the whitspace after the "width height"
		// 2D array allocation
		map = new char * [height];
		if(map == 0)	// if the memory was able to allocate
			return false;
		for(int i = 0; i < height; i++)
		{
			map[i] = new char [width];
		}
		// data loading algorithm
		int x = 0, y = 0, letter;
		bool done = false;
		while(!done)
		{
			letter = infile.get();
			if(letter == EOF)
			{
				done = true;
			}
			else if(letter != '\n' 
				&& letter != '\r' 
				&& letter != EOF)
			{
				map[y][x] = letter;
				x++;
				if(x >= width)
				{
					y++;
					x = 0;
					if(y >= height)
					{
						done = true;
					}
				}
			}
		}
		return true;
	}

	/**
	 * prints the 2D array to the stdio console (printf) at the
	 * given x/y coordinate (with 0,0 at the top left)
	 */
	void draw(Rect * dirtyRectangle, int a_x, int a_y, char transparentChar)
	{
		// print out the array to make sure it's working like I want.
		for(int y = 0; y < height; y++)
		{
			for(int x = 0; x < width; x++)
			{
				char letter = map[y][x];
				if(letter != transparentChar
				&& (!dirtyRectangle 
				|| dirtyRectangle->contains(V2D<int>(x,y))))
				{
					gotoxy(a_x+x, a_y+y);
					printf("%c", letter);
				}
			}
		}
	}

	void draw(int x, int y)
	{
		draw(0, x, y, ' ');
	}

	/** does a simple print to the stdio console (printf) */
	void draw()
	{
		draw(x, y);
	}

	void drawFlippedH(int a_x, int a_y)
	{
		// print out the array to make sure it's working like I want.
		for(int y = 0; y < height; y++)
		{
			gotoxy(a_x, a_y+y);
			for(int x = 0; x < width; x++)
			{
				char letter = map[y][(width-1)-x];
				printf("%c", letter);
			}
		}
	}
	void drawFlippedV(int a_x, int a_y)
	{
		// print out the array to make sure it's working like I want.
		for(int y = 0; y < height; y++)
		{
			gotoxy(a_x, a_y+y);
			for(int x = 0; x < width; x++)
			{
				char letter = map[(height-1)-y][x];
				printf("%c", letter);
			}
		}
	}
	void drawFlippedXY(int a_x, int a_y)
	{
		// print out the array to make sure it's working like I want.
		for(int y = 0; y < width; y++)
		{
			gotoxy(a_x, a_y+y);
			for(int x = 0; x < height; x++)
			{
				char letter = map[x][y];
				printf("%c", letter);
			}
		}
	}

	void drawRotatedCW(int a_x, int a_y)
	{
		// print out the array to make sure it's working like I want.
		for(int y = 0; y < width; y++)
		{
			gotoxy(a_x, a_y+y);
			for(int x = 0; x < height; x++)
			{
				char letter = map[(height-1)-x][y];
				printf("%c", letter);
			}
		}
	}
	void drawRotatedCCW(int a_x, int a_y)
	{
		// print out the array to make sure it's working like I want.
		for(int y = 0; y < width; y++)
		{
			gotoxy(a_x, a_y+y);
			for(int x = 0; x < height; x++)
			{
				char letter = map[x][(width-1)-y];
				printf("%c", letter);
			}
		}
	}

	/** clean up the memory used by this */
	void release()
	{
		if(map)
		{
			for(int i = 0; i < height; i++)
				delete map[i];
			delete map;
		}
		map = 0;
		height = 0;
		width = 0;
	}
	/** horizontally flips the 2D array in place */
	void flipH()
	{
		for(int y = 0; y < height; y++)
		{
			for(int x = 0; x < width/2; x++)
			{
				char temp = map[y][x];
				map[y][x] = map[y][(width-1)-x];
				map[y][(width-1)-x] = temp;
				//a[y][x] = map[y][(width-1)-x];
			}
		}
	}
	void flipV()
	{
		for(int y = 0; y < height/2; y++)
		{
			for(int x = 0; x < width; x++)
			{
				char temp = map[y][x];
				map[y][x] = map[(height-1)-y][x];
				map[(height-1)-y][x] = temp;
			}
		}
	}
	/** horizontally flips the 2D array by copying it into another array */
	void flipXY()
	{
		int newH = width;
		int newW = height;
		char ** a = new char * [newH];
		for(int i = 0; i < newH; i++)
		{
			a[i] = new char[newW];
		}
		// print out the array to make sure it's working like I want.
		for(int y = 0; y < height; y++)
		{
			for(int x = 0; x < width; x++)
			{
				a[x][y] = map[y][x];
			}
		}
		// get rid of the old data
		release();
		// replace the old data with the new data
		map = a;
		height = newH;
		width = newW;
	}
	void rotateCW()
	{
		flipXY();
		flipH();
	}
	void rotateCCW()
	{
		flipXY();
		flipV();
	}

	~Map()
	{
		release();
	}
};